[자동차 경주] 이지섭 미션 제출합니다.#57
Conversation
경주 생성과 관련된 기능 추가: - 입력 및 입력 예외처리 - 경주에 참여하는 자동차와 경주 생성
다음과 같은 이름으로 함수화: - getInputCarName(): 자동차 이름 입력 및 예외처리 - splitCarName(name): 입력 받은 이름에서 각 자동차 이름 추출 및 예외처리 - getInputRound(): 차수 입력 및 예외처리
작은 오류 수정: - 초기 차수 수정 과정에서 잘못 수정한 Car.position 초기값 복구
기능 분리 - RacingGame.play() 하위 로직을 함수로 세분화 - RacingGame.play()에서는 경주만 진행하도록 수정 - RacingGame.getWinners() 추가로 RacingGame은 데이터만 제공 - 최종 우승자 출력은 printOutput(List<Car>)에서 담당하도록 분리
테스트를 위한 가시성 수정자 변경: - 기능 테스트의 대상이 되는 주요 입출력 함수들을 public으로 전환
기능 분리: - Car 클래스 생성 기능 분리 기능 수정: - getInputRound()의 반환 타입을 String으로 변경 - getInputCarNames()에서 공백에 따른 에러 메시지 일관성을 위해 require() 순서 조정 - RacingGame.printRoundResult()의 map()을 forEach()로 변경 변수명 변경: - getInputCarNames()의 hasNonCommaSpecialChar를 hasInvalidChar로 변경 - map()에서 it가 Car인 경우 중 일부를 car로 표기
다음과 같은 기능들의 테스트 코드 수정: - getInputRound()의 반환값을 String으로 수정 - stringToInt() 테스트 추가 및 splitCarName()과 InputProcessingTest로 묶음 - getInputCarNames()의 require() 순서가 달라짐에 따라 공백 관련 테스트 추가
InputView 추가: - main/kotlin/racingcar에 view 디렉토리 및 InputView.kt 추가 - 입력에 포함되었던 유효 입력 검사 기능을 축출하여 축소
Application.kt의 불필요한 Console import 제거
validateCarNamesInput() 함수에서 자동차 이름 입력 검증을 담당하도록 수정
로직 변경 사항에 따라 수정: - InputView를 통해 입력을 받도록 수정 - 입력 시 검증을 하지 않도록 변경됨에 따라 입력 검증하는 테스트를 제거
실수로 반영되지 않은 사항 반영: - 차수 입력 기능 테스트 중 inputView 누락 수정 - 예외 처리 테스트 제거
InputTest.kt에서 사용하지 않는 assertThrows에 대한 import 제거
|
|
||
| import camp.nextstep.edu.missionutils.Console | ||
|
|
||
| class InputView { |
There was a problem hiding this comment.
일반적인 형식의 class로 만드시는 것보다 object class 형식으로 정의하시면 더 보기 좋은 코드가 될 거 같습니다!
There was a problem hiding this comment.
InputView만 따로 view 폴더에 빼신 이유가 궁금합니다.
과제 마지막에 MVC를 조금이라도 적용해보려다 보니 입력 기능만 따로 빼게 되었습니다
There was a problem hiding this comment.
일반적인 형식의 class로 만드시는 것보다 object class 형식으로 정의하시면 더 보기 좋은 코드가 될 거 같습니다!
찾아보니 싱글톤 객체라는 개념이 있네요! 감사합니다.
| } | ||
|
|
||
| fun getWinners(): List<Car> { | ||
| check(this.isFinished()) { "게임이 아직 시작되지 않았습니다." } |
There was a problem hiding this comment.
check를 통해 모든 라운드가 끝났는지 검사하시는 것 같습니다. 그런데, 이미 play 함수에서 isFinished를 사용해서 반복문을 검사하고 있는데 이 부분이 또 필요한 지 모르겠습니다.
There was a problem hiding this comment.
check를 통해 모든 라운드가 끝났는지 검사하시는 것 같습니다. 그런데, 이미 play 함수에서 isFinished를 사용해서 반복문을 검사하고 있는데 이 부분이 또 필요한 지 모르겠습니다.
RacingGame.getWinners() 메서드를 RacingGame.play()를 호출하기 이전에 호출하는 경우가 존재할 수 있다고 생각했습니다.
생각해보니 굳이 한번 더 체크하기보다는 널이나 빈 리스트를 반환해도 될 것 같네요.
| 0 | ||
| } | ||
|
|
||
| fun printOutput(winners: List<Car>?) { |
There was a problem hiding this comment.
InputView는 만드셨는데 OutputView는 따로 만드시지 않았네요. printOutput에서 우승자 출력을 결정하시는데 OutputView.kt를 따로 만드셔서 분리하시는 게 좋을 거 같습니다~
BaekCCI
left a comment
There was a problem hiding this comment.
플로우 차트를 설계해서 구현하신 점이 인상적이네요!
전체적으로 로직이 하나의 파일에 모여 있어서 다소 복잡해 보이는 것 같습니다.
비슷한 역할이나 처리 단위를 가진 함수들을 object나 class로 묶어서 별도의 파일로 분리하면
구조가 명확해지고 코드 가독성도 좋아질 것 같습니다.
2주차 고생하셨습니다!!
| fun stringToInt(roundInput: String): Int = if (roundInput.isNotBlank()) { | ||
| roundInput.toIntOrNull() ?: throw IllegalArgumentException("숫자를 입력해주세요.") | ||
| } else { | ||
| 0 | ||
| } |
There was a problem hiding this comment.
빈 값을 입력하면 0으로 반환하도록 처리하셨는데,
이렇게 되면 게임 결과 계산 시 모든 유저가 우승으로 처리될 것 같습니다.
해당 케이스를 에러로 처리하지 않고 0을 반환하도록 하신 이유가 궁금합니다!
또한 가독성을 위해서 명시적으로 return을 사용하는 형태로 바꾸면 더 읽기 쉬울 것 같습니다!
| fun stringToInt(roundInput: String): Int = if (roundInput.isNotBlank()) { | |
| roundInput.toIntOrNull() ?: throw IllegalArgumentException("숫자를 입력해주세요.") | |
| } else { | |
| 0 | |
| } | |
| fun stringToInt(roundInput: String): Int { | |
| if (roundInput.isNotBlank()) { | |
| return roundInput.toIntOrNull() ?: throw IllegalArgumentException("숫자를 입력해주세요.") | |
| } | |
| return 0 | |
| } |
There was a problem hiding this comment.
빈 값을 입력하면 0으로 반환하도록 처리하셨는데, 이렇게 되면 게임 결과 계산 시 모든 유저가 우승으로 처리될 것 같습니다. 해당 케이스를 에러로 처리하지 않고 0을 반환하도록 하신 이유가 궁금합니다!
이건 제 요구사항 분석 과정에서 잘못된 판단이 들어간 것 같습니다. 말씀하신 대로 round 입력이 0이거나 들어오지 않을 경우에는 모종의 이유로 게임 개최는 했지만 진행할 수 없는 상황이라고 판단하고 모든 유저가 우승자가 되도록 구현했습니다.
지금 생각해보니 IllegalArgumentException을 발생시키거나 우승자가 없도록 하는 것이 더 올바른 구현일 것 같네요.
| fun play() { | ||
| println() | ||
| println("실행 결과") | ||
| while (!this.isFinished()) { |
There was a problem hiding this comment.
반복문이 돌 때마다 isFinished()로 비교하는 것보다
repeat(round)나 for 문을 활용하면 불필요한 비교 연산을 줄일 수 있을 것 같습니다.
그렇게 하면 currentRound 변수도 없어져서 코드가 좀 더 단순해질 것 같아요!
또한 클래스 내부 메서드 호출 시에 this를 반복적으로 사용하셨는데,
스코프가 명확한 상황에서는 this를 생략해도 되기 때문에
제거하면 코드가 조금 더 깔끔해질 것 같습니다.
|
|
||
| import camp.nextstep.edu.missionutils.Console | ||
|
|
||
| class InputView { |
📝 기능 목록
경주 생성
예외 처리
예외 처리
경주 진행
경주 결과 출력
🔃플로우 차트
--- title: 자동차 경주 --- flowchart TD subgraph INIT[경주 생성] inputCarName[자동차 이름 입력] -->|입력 조건 예외 처리| inputRound[시도할 횟수 입력] inputRound --> createCar[경주와 경주의 자동차 생성] end INIT --> Game subgraph Game[경주 진행] initCurrentRound[현재 차수 = 1] initCurrentRound --> isRoundNotFinished isRoundNotFinished{현재 차수 <= 입력된 시도 횟수} isRoundNotFinished -- YES --> extractRandomInt isRoundNotFinished -- NO -----> winnerSelection["움직임 데이터가 가장 큰 우승자(들) 선정"] winnerSelection --> END extractRandomInt["자동차마다 0~9 사이의 값 추출"] extractRandomInt --> isCanMove isCanMove{추출된 값 >= 4} isCanMove -- YES --> move isCanMove -- NO --> printRound move[움직임 데이터 1 증가] move --> printRound printRound[자동차마다 차수별 실행 결과 출력] printRound --> isRoundNotFinished end Game --> printResult subgraph printResult[결과 출력하기] printWinner[최종 우승자 출력] end